#define NORTH 0
#define NORTHEAST 1
#define EAST 2
#define SOUTHEAST 3
#define SOUTH 4
#define SOUTHWEST 5
#define WEST 6
#define NORTHWEST 7
#define CENTER 8
#define TRIANGLE_VERTICES 3
#define VERTEX_COORDINATES 3

void calculateIndices(global uint* indices);
void calculateVertices(global const float* altitudes, global float* vertices);
void calculateNormals(global const float* vertices, global float* normals);

kernel void map(global const float* altitudes, global uint* indices, global float* vertices, global float* normals) {
	private const size_t latitudinalSize = get_global_size(0);
	private const size_t longitudinalSize = get_global_size(1);
	private const size_t directionalSize = get_global_size(2);
	private const size_t latitude = get_global_id(0);
	private const size_t longitude = get_global_id(1);
	private const size_t direction = get_global_id(2);
	if ((latitude < latitudinalSize) && (longitude < longitudinalSize) && (direction < directionalSize)) {
		calculateIndices(indices);
		calculateVertices(altitudes, vertices);
		barrier(CLK_GLOBAL_MEM_FENCE);
		calculateNormals(vertices, normals);
	}
}

void calculateIndices(global uint* indices) {
	private const size_t longitudinalSize = get_global_size(1);
	private const size_t directionalSize = get_global_size(2);
	private const size_t latitude = get_global_id(0);
	private const size_t longitude = get_global_id(1);
	private const size_t direction = get_global_id(2);
	private const uint indexOffset = latitude * longitudinalSize * CENTER * TRIANGLE_VERTICES + longitude * CENTER * TRIANGLE_VERTICES + direction * TRIANGLE_VERTICES;
	private const uint indexBase = latitude * longitudinalSize * directionalSize + longitude * directionalSize;
	switch (direction) {
	case NORTH:
		indices[indexOffset] = indexBase + NORTH;
		indices[indexOffset + 1] = indexBase + CENTER;
		indices[indexOffset + 2]= indexBase + NORTHEAST;
		break;
	case NORTHEAST:
		indices[indexOffset] = indexBase + NORTHEAST;
		indices[indexOffset + 1] = indexBase + CENTER;
		indices[indexOffset + 2]= indexBase + EAST;
		break;
	case EAST:
		indices[indexOffset] = indexBase + EAST;
		indices[indexOffset + 1] = indexBase + CENTER;
		indices[indexOffset + 2]= indexBase + SOUTHEAST;
		break;
	case SOUTHEAST:
		indices[indexOffset] = indexBase + SOUTHEAST;
		indices[indexOffset + 1] = indexBase + CENTER;
		indices[indexOffset + 2]= indexBase + SOUTH;
		break;
	case SOUTH:
		indices[indexOffset] = indexBase + SOUTH;
		indices[indexOffset + 1] = indexBase + CENTER;
		indices[indexOffset + 2]= indexBase + SOUTHWEST;
		break;
	case SOUTHWEST:
		indices[indexOffset] = indexBase + SOUTHWEST;
		indices[indexOffset + 1] = indexBase + CENTER;
		indices[indexOffset + 2]= indexBase + WEST;
		break;
	case WEST:
		indices[indexOffset] = indexBase + WEST;
		indices[indexOffset + 1] = indexBase + CENTER;
		indices[indexOffset + 2]= indexBase + NORTHWEST;
		break;
	case NORTHWEST:
		indices[indexOffset] = indexBase + NORTHWEST;
		indices[indexOffset + 1] = indexBase + CENTER;
		indices[indexOffset + 2]= indexBase + NORTH;
	}
}

void calculateVertices(global const float* altitudes, global float* vertices) {
	private const size_t latitudinalSize = get_global_size(0);
	private const size_t longitudinalSize = get_global_size(1);
	private const size_t directionalSize = get_global_size(2);
	private const size_t latitude = get_global_id(0);
	private const size_t longitude = get_global_id(1);
	private const size_t direction = get_global_id(2);
	private const uint altitudesOffset = latitude * longitudinalSize + longitude;
	private const uint vertexOffset = latitude * longitudinalSize * directionalSize * VERTEX_COORDINATES + longitude * directionalSize * VERTEX_COORDINATES + direction * VERTEX_COORDINATES;
	switch (direction) {
	case NORTH:
		vertices[vertexOffset] = (float) longitude + 0.5f;
		if (latitude + 1 < latitudinalSize)
			vertices[vertexOffset + 1] = (altitudes[altitudesOffset] + altitudes[altitudesOffset + longitudinalSize]) / 2.0f;
		else
			vertices[vertexOffset + 1] = altitudes[altitudesOffset];
		vertices[vertexOffset + 2] = -(float) latitude - 1.0f;
		break;
	case NORTHEAST:
		vertices[vertexOffset] = (float) longitude + 1.0f;
		if (((latitude + 1 < latitudinalSize) && (longitude + 1 < longitudinalSize)))
			vertices[vertexOffset + 1] = (altitudes[altitudesOffset] + altitudes[altitudesOffset + longitudinalSize] + altitudes[altitudesOffset + longitudinalSize + 1] + altitudes[altitudesOffset + 1]) / 4.0f;
		else if (latitude + 1 < latitudinalSize)
			vertices[vertexOffset + 1] = (altitudes[altitudesOffset] + altitudes[altitudesOffset + longitudinalSize]) / 2.0f;
		else if (longitude + 1 < longitudinalSize)
			vertices[vertexOffset + 1] = (altitudes[altitudesOffset] + altitudes[altitudesOffset + 1]) / 2.0f;
		else
			vertices[vertexOffset + 1] = altitudes[altitudesOffset];
		vertices[vertexOffset + 2] = -(float) latitude - 1.0f;
		break;
	case EAST:
		vertices[vertexOffset] = (float) longitude + 1.0f;
		if (longitude + 1 < longitudinalSize)
			vertices[vertexOffset + 1] = (altitudes[altitudesOffset] + altitudes[altitudesOffset + 1]) / 2.0f;
		else
			vertices[vertexOffset + 1] = altitudes[altitudesOffset];
		vertices[vertexOffset + 2] = -(float) latitude - 0.5f;
		break;
	case SOUTHEAST:
		vertices[vertexOffset] = (float) longitude + 1.0f;
		if ((latitude > 0) && (longitude + 1 < longitudinalSize))
			vertices[vertexOffset + 1] = (altitudes[altitudesOffset] + altitudes[altitudesOffset + 1] + altitudes[altitudesOffset - longitudinalSize + 1] + altitudes[altitudesOffset - longitudinalSize]) / 4.0f;
		else if (latitude > 0)
			vertices[vertexOffset + 1] = (altitudes[altitudesOffset] + altitudes[altitudesOffset - longitudinalSize]) / 2.0f;
		else if (longitude + 1 < longitudinalSize)
			vertices[vertexOffset + 1] = (altitudes[altitudesOffset] + altitudes[altitudesOffset + 1]) / 2.0f;
		else
			vertices[vertexOffset + 1] = altitudes[altitudesOffset];
		vertices[vertexOffset + 2] = -(float) latitude;
		break;
	case SOUTH:
		vertices[vertexOffset] = (float) longitude + 0.5f;
		if (latitude > 0)
			vertices[vertexOffset + 1] = (altitudes[altitudesOffset] + altitudes[altitudesOffset - longitudinalSize]) / 2.0f;
		else
			vertices[vertexOffset + 1] = altitudes[altitudesOffset];
		vertices[vertexOffset + 2] = -(float) latitude;
		break;
	case SOUTHWEST:
		vertices[vertexOffset] = (float) longitude;
		if ((latitude > 0) && (longitude > 0))
			vertices[vertexOffset + 1] = (altitudes[altitudesOffset] + altitudes[altitudesOffset - longitudinalSize] + altitudes[altitudesOffset - longitudinalSize - 1] + altitudes[altitudesOffset - 1]) / 4.0f;
		else if (latitude > 0)
			vertices[vertexOffset + 1] = (altitudes[altitudesOffset] + altitudes[altitudesOffset - longitudinalSize]) / 2.0f;
		else if (longitude > 0)
			vertices[vertexOffset + 1] = (altitudes[altitudesOffset] + altitudes[altitudesOffset - 1]) / 2.0f;
		else
			vertices[vertexOffset + 1] = altitudes[altitudesOffset];
		vertices[vertexOffset + 2] = -(float) latitude;
		break;
	case WEST:
		vertices[vertexOffset] = (float) longitude;
		if (longitude > 0)
			vertices[vertexOffset + 1] = (altitudes[altitudesOffset] + altitudes[altitudesOffset - 1]) / 2.0f;
		else
			vertices[vertexOffset + 1] = altitudes[altitudesOffset];
		vertices[vertexOffset + 2] = -(float) latitude - 0.5f;
		break;
	case NORTHWEST:
		vertices[vertexOffset] = (float) longitude;
		if ((latitude + 1 < latitudinalSize) && (longitude > 0))
			vertices[vertexOffset + 1] = (altitudes[altitudesOffset] + altitudes[altitudesOffset - 1] + altitudes[altitudesOffset + longitudinalSize - 1] + altitudes[altitudesOffset + longitudinalSize]) / 4.0f;
		else if (latitude + 1 < latitudinalSize)
			vertices[vertexOffset + 1] = (altitudes[altitudesOffset] + altitudes[altitudesOffset + longitudinalSize]) / 2.0f;
		else if (longitude > 0)
			vertices[vertexOffset + 1] = (altitudes[altitudesOffset] + altitudes[altitudesOffset - 1]) / 2.0f;
		else
			vertices[vertexOffset + 1] = altitudes[altitudesOffset];
		vertices[vertexOffset + 2] = -(float) latitude - 1.0f;
		break;
	case CENTER:
		vertices[vertexOffset] = (float) longitude + 0.5f;
		vertices[vertexOffset + 1] = altitudes[altitudesOffset];
		vertices[vertexOffset + 2] = -(float) latitude - 0.5f;
	}
}

void calculateNormals(global const float* vertices, global float* normals) {
	private const size_t latitudinalSize = get_global_size(0);
	private const size_t longitudinalSize = get_global_size(1);
	private const size_t directionalSize = get_global_size(2);
	private const size_t latitude = get_global_id(0);
	private const size_t longitude = get_global_id(1);
	private const size_t direction = get_global_id(2);
	private const uint vertexOffset = latitude * longitudinalSize * directionalSize * VERTEX_COORDINATES + longitude * directionalSize * VERTEX_COORDINATES + direction * VERTEX_COORDINATES;
	private uint vertexOffsetNorth = 0;
	private uint vertexOffsetNortheast = 0;
	private uint vertexOffsetEast = 0;
	private uint vertexOffsetSoutheast = 0;
	private uint vertexOffsetSouth = 0;
	private uint vertexOffsetSouthwest = 0;
	private uint vertexOffsetWest = 0;
	private uint vertexOffsetNorthwest = 0;
	private float3 vertexCenter = (float3) (0.0f, 0.0f, 0.0f);
	private float3 vertexNorth = (float3) (0.0f, 0.0f, 0.0f);
	private float3 vertexNortheast = (float3) (0.0f, 0.0f, 0.0f);
	private float3 vertexEast = (float3) (0.0f, 0.0f, 0.0f);
	private float3 vertexSoutheast = (float3) (0.0f, 0.0f, 0.0f);
	private float3 vertexSouth = (float3) (0.0f, 0.0f, 0.0f);
	private float3 vertexSouthwest = (float3) (0.0f, 0.0f, 0.0f);
	private float3 vertexWest = (float3) (0.0f, 0.0f, 0.0f);
	private float3 vertexNorthwest = (float3) (0.0f, 0.0f, 0.0f);
	private float3 normalNorth = (float3) (0.0f, 0.0f, 0.0f);
	private float3 normalNorthNortheast = (float3) (0.0f, 0.0f, 0.0f);
	private float3 normalNortheast = (float3) (0.0f, 0.0f, 0.0f);
	private float3 normalNortheastEast = (float3) (0.0f, 0.0f, 0.0f);
	private float3 normalEast = (float3) (0.0f, 0.0f, 0.0f);
	private float3 normalEastSoutheast = (float3) (0.0f, 0.0f, 0.0f);
	private float3 normalSoutheast = (float3) (0.0f, 0.0f, 0.0f);
	private float3 normalSoutheastSouth = (float3) (0.0f, 0.0f, 0.0f);
	private float3 normalSouth = (float3) (0.0f, 0.0f, 0.0f);
	private float3 normalSouthSouthwest = (float3) (0.0f, 0.0f, 0.0f);
	private float3 normalSouthwest = (float3) (0.0f, 0.0f, 0.0f);
	private float3 normalSouthwestWest = (float3) (0.0f, 0.0f, 0.0f);
	private float3 normalWest = (float3) (0.0f, 0.0f, 0.0f);
	private float3 normalWestNorthwest = (float3) (0.0f, 0.0f, 0.0f);
	private float3 normalNorthwest = (float3) (0.0f, 0.0f, 0.0f);
	private float3 normalNorthwestNorth = (float3) (0.0f, 0.0f, 0.0f);
	private float3 normal = (float3) (0.0f, 0.0f, 0.0f);
	switch (direction) {
	case NORTH:
		vertexOffsetEast = vertexOffset + (NORTHEAST - NORTH) * VERTEX_COORDINATES;
		vertexOffsetSouth = vertexOffset + (CENTER - NORTH) * VERTEX_COORDINATES;
		vertexOffsetWest = vertexOffset + (NORTHWEST - NORTH) * VERTEX_COORDINATES;
		vertexCenter = (float3) (vertices[vertexOffset], vertices[vertexOffset + 1], vertices[vertexOffset + 2]);
		vertexEast = (float3) (vertices[vertexOffsetEast], vertices[vertexOffsetEast + 1], vertices[vertexOffsetEast + 2]);
		vertexSouth = (float3) (vertices[vertexOffsetSouth], vertices[vertexOffsetSouth + 1], vertices[vertexOffsetSouth + 2]);
		vertexWest = (float3) (vertices[vertexOffsetWest], vertices[vertexOffsetWest + 1], vertices[vertexOffsetWest + 2]);
		normalSoutheast = normalize(cross(vertexSouth - vertexCenter, vertexEast - vertexCenter));
		normalSouthwest = normalize(cross(vertexWest - vertexCenter, vertexSouth - vertexCenter));
		if (latitude + 1 < latitudinalSize) {
			vertexOffsetNorth = vertexOffset + longitudinalSize * directionalSize * VERTEX_COORDINATES + (CENTER - NORTH) * VERTEX_COORDINATES;
			vertexNorth = (float3) (vertices[vertexOffsetNorth], vertices[vertexOffsetNorth + 1], vertices[vertexOffsetNorth + 2]);
			normalNortheast = normalize(cross(vertexEast - vertexCenter, vertexNorth - vertexCenter));
			normalNorthwest = normalize(cross(vertexNorth - vertexCenter, vertexWest - vertexCenter));
			normal = (normalNortheast + normalSoutheast + normalSouthwest + normalNorthwest) / 4.0f;
		} else
			normal = (normalSoutheast + normalSouthwest) / 2.0f;
		break;
	case NORTHEAST:
		vertexOffsetSouth = vertexOffset + (EAST - NORTHEAST) * VERTEX_COORDINATES;
		vertexOffsetSouthwest = vertexOffset + (CENTER - NORTHEAST) * VERTEX_COORDINATES;
		vertexOffsetWest = vertexOffset + (NORTH - NORTHEAST) * VERTEX_COORDINATES;
		vertexCenter = (float3) (vertices[vertexOffset], vertices[vertexOffset + 1], vertices[vertexOffset + 2]);
		vertexSouth = (float3) (vertices[vertexOffsetSouth], vertices[vertexOffsetSouth + 1], vertices[vertexOffsetSouth + 2]);
		vertexSouthwest = (float3) (vertices[vertexOffsetSouthwest], vertices[vertexOffsetSouthwest + 1], vertices[vertexOffsetSouthwest + 2]);
		vertexWest = (float3) (vertices[vertexOffsetWest], vertices[vertexOffsetWest + 1], vertices[vertexOffsetWest + 2]);
		normalSouthSouthwest = normalize(cross(vertexSouthwest - vertexCenter, vertexSouth - vertexCenter));
		normalSouthwestWest = normalize(cross(vertexWest - vertexCenter, vertexSouthwest - vertexCenter));
		if ((latitude + 1 < latitudinalSize) && (longitude + 1 < longitudinalSize)) {
			vertexOffsetNorth = vertexOffset + longitudinalSize * directionalSize * VERTEX_COORDINATES + directionalSize * VERTEX_COORDINATES + (WEST - NORTHEAST) * VERTEX_COORDINATES;
			vertexOffsetNortheast = vertexOffset + longitudinalSize * directionalSize * VERTEX_COORDINATES + directionalSize * VERTEX_COORDINATES + (CENTER - NORTHEAST) * VERTEX_COORDINATES;
			vertexOffsetEast = vertexOffset + longitudinalSize * directionalSize * VERTEX_COORDINATES + directionalSize * VERTEX_COORDINATES + (SOUTH - NORTHEAST) * VERTEX_COORDINATES;
			vertexOffsetSoutheast = vertexOffset + directionalSize * VERTEX_COORDINATES + (CENTER - NORTHEAST) * VERTEX_COORDINATES; 
			vertexOffsetNorthwest = vertexOffset + longitudinalSize * directionalSize * VERTEX_COORDINATES + (CENTER - NORTHEAST) * VERTEX_COORDINATES;
			vertexNorth = (float3) (vertices[vertexOffsetNorth], vertices[vertexOffsetNorth + 1], vertices[vertexOffsetNorth + 2]);
			vertexNortheast = (float3) (vertices[vertexOffsetNortheast], vertices[vertexOffsetNortheast + 1], vertices[vertexOffsetNortheast + 2]);
			vertexEast = (float3) (vertices[vertexOffsetEast], vertices[vertexOffsetEast + 1], vertices[vertexOffsetEast + 2]);
			vertexSoutheast = (float3) (vertices[vertexOffsetSoutheast], vertices[vertexOffsetSoutheast + 1], vertices[vertexOffsetSoutheast + 2]);
			vertexNorthwest = (float3) (vertices[vertexOffsetNorthwest], vertices[vertexOffsetNorthwest + 1], vertices[vertexOffsetNorthwest + 2]);
			normalNorthNortheast = normalize(cross(vertexNortheast - vertexCenter, vertexNorth - vertexCenter));
			normalNortheastEast = normalize(cross(vertexEast - vertexCenter, vertexNortheast - vertexCenter));
			normalEastSoutheast = normalize(cross(vertexSoutheast - vertexCenter, vertexEast - vertexCenter));
			normalSoutheastSouth = normalize(cross(vertexSouth - vertexCenter, vertexSoutheast - vertexCenter));
			normalWestNorthwest = normalize(cross(vertexNorthwest - vertexCenter, vertexWest - vertexCenter));
			normalNorthwestNorth = normalize(cross(vertexNorth - vertexCenter, vertexNorthwest - vertexCenter));
			normal = (normalNorthNortheast + normalNortheastEast + normalEastSoutheast + normalSoutheastSouth + normalSouthSouthwest + normalSouthwestWest + normalWestNorthwest + normalNorthwestNorth) / 8.0f;	
		} else if (latitude + 1 < latitudinalSize) {
			vertexOffsetNorth = vertexOffset + longitudinalSize * directionalSize * VERTEX_COORDINATES + (EAST - NORTHEAST) * VERTEX_COORDINATES;
			vertexOffsetNorthwest = vertexOffset + longitudinalSize * directionalSize * VERTEX_COORDINATES + (CENTER - NORTHEAST) * VERTEX_COORDINATES;
			vertexNorth = (float3) (vertices[vertexOffsetNorth], vertices[vertexOffsetNorth + 1], vertices[vertexOffsetNorth + 2]);
			vertexNorthwest = (float3) (vertices[vertexOffsetNorthwest], vertices[vertexOffsetNorthwest + 1], vertices[vertexOffsetNorthwest + 2]);
			normalWestNorthwest = normalize(cross(vertexNorthwest - vertexCenter, vertexWest - vertexCenter));
			normalNorthwestNorth = normalize(cross(vertexNorth - vertexCenter, vertexNorthwest - vertexCenter));
			normal = (normalSouthSouthwest + normalSouthwestWest + normalWestNorthwest + normalNorthwestNorth) / 4.0f;	
		} else if (longitude + 1 < longitudinalSize) {
			vertexOffsetEast = vertexOffset + directionalSize * VERTEX_COORDINATES + directionalSize * VERTEX_COORDINATES + (NORTH - NORTHEAST) * VERTEX_COORDINATES;
			vertexOffsetSoutheast = vertexOffset + directionalSize * VERTEX_COORDINATES + (CENTER - NORTHEAST) * VERTEX_COORDINATES; 
			vertexEast = (float3) (vertices[vertexOffsetEast], vertices[vertexOffsetEast + 1], vertices[vertexOffsetEast + 2]);
			vertexSoutheast = (float3) (vertices[vertexOffsetSoutheast], vertices[vertexOffsetSoutheast + 1], vertices[vertexOffsetSoutheast + 2]);
			normalEastSoutheast = normalize(cross(vertexSoutheast - vertexCenter, vertexEast - vertexCenter));
			normalSoutheastSouth = normalize(cross(vertexSouth - vertexCenter, vertexSoutheast - vertexCenter));
			normal = (normalEastSoutheast + normalSoutheastSouth + normalSouthSouthwest + normalSouthwestWest) / 4.0f;		
		} else
			normal = (normalSouthSouthwest + normalSouthwestWest) / 2.0f;
		break;
	case EAST:
		vertexOffsetNorth = vertexOffset + (NORTHEAST - EAST) * VERTEX_COORDINATES;
		vertexOffsetSouth = vertexOffset + (SOUTHEAST - EAST) * VERTEX_COORDINATES;
		vertexOffsetWest = vertexOffset + (CENTER - EAST) * VERTEX_COORDINATES;
		vertexCenter = (float3) (vertices[vertexOffset], vertices[vertexOffset + 1], vertices[vertexOffset + 2]);
		vertexNorth = (float3) (vertices[vertexOffsetNorth], vertices[vertexOffsetNorth + 1], vertices[vertexOffsetNorth + 2]);
		vertexSouth = (float3) (vertices[vertexOffsetSouth], vertices[vertexOffsetSouth + 1], vertices[vertexOffsetSouth + 2]);
		vertexWest = (float3) (vertices[vertexOffsetWest], vertices[vertexOffsetWest + 1], vertices[vertexOffsetWest + 2]);
		normalSouthwest = normalize(cross(vertexWest - vertexCenter, vertexSouth - vertexCenter));
		normalNorthwest = normalize(cross(vertexNorth - vertexCenter, vertexWest - vertexCenter));
		if (longitude + 1 < longitudinalSize) {
			vertexOffsetEast = vertexOffset + directionalSize * VERTEX_COORDINATES + (CENTER - EAST) * VERTEX_COORDINATES;
			vertexEast = (float3) (vertices[vertexOffsetEast], vertices[vertexOffsetEast + 1], vertices[vertexOffsetEast + 2]);
			normalNortheast = normalize(cross(vertexEast - vertexCenter, vertexNorth - vertexCenter));
			normalSoutheast = normalize(cross(vertexSouth - vertexCenter, vertexEast - vertexCenter));
			normal = (normalNortheast + normalSoutheast + normalSouthwest + normalNorthwest) / 4.0f;
		} else
			normal = (normalSouthwest + normalNorthwest) / 2.0f;
		break;
	case SOUTHEAST:
		normal = (float3) (0.0f, -1.0f, 0.0f);
		break;
	case SOUTH:
		vertexOffsetNorth = vertexOffset + (CENTER - SOUTH) * VERTEX_COORDINATES;
		vertexOffsetEast = vertexOffset + (SOUTHEAST - SOUTH) * VERTEX_COORDINATES;
		vertexOffsetWest = vertexOffset + (SOUTHWEST - SOUTH) * VERTEX_COORDINATES;
		vertexCenter = (float3) (vertices[vertexOffset], vertices[vertexOffset + 1], vertices[vertexOffset + 2]);
		vertexNorth = (float3) (vertices[vertexOffsetNorth], vertices[vertexOffsetNorth + 1], vertices[vertexOffsetNorth + 2]);
		vertexEast = (float3) (vertices[vertexOffsetEast], vertices[vertexOffsetEast + 1], vertices[vertexOffsetEast + 2]);
		vertexWest = (float3) (vertices[vertexOffsetWest], vertices[vertexOffsetWest + 1], vertices[vertexOffsetWest + 2]);
		normalNortheast = normalize(cross(vertexEast - vertexCenter, vertexNorth - vertexCenter));
		normalNorthwest = normalize(cross(vertexNorth - vertexCenter, vertexWest - vertexCenter));
		if (latitude > 0) {
			vertexOffsetSouth = vertexOffset - longitudinalSize * directionalSize * VERTEX_COORDINATES + (CENTER - SOUTH) * VERTEX_COORDINATES;
			vertexSouth = (float3) (vertices[vertexOffsetSouth], vertices[vertexOffsetSouth + 1], vertices[vertexOffsetSouth + 2]);
			normalSoutheast = normalize(cross(vertexSouth - vertexCenter, vertexEast - vertexCenter));
			normalSouthwest = normalize(cross(vertexWest - vertexCenter, vertexSouth - vertexCenter));
			normal = (normalNortheast + normalSoutheast + normalSouthwest + normalNorthwest) / 4.0f;
		} else
			normal = (normalNortheast + normalNorthwest) / 2.0f;
		break;
	case SOUTHWEST:
		normal = (float3) (0.0f, -1.0f, 0.0f);
		break;
	case WEST:
		vertexOffsetNorth = vertexOffset + (NORTHWEST - WEST) * VERTEX_COORDINATES;
		vertexOffsetEast = vertexOffset + (CENTER - WEST) * VERTEX_COORDINATES;
		vertexOffsetSouth = vertexOffset + (SOUTHWEST - WEST) * VERTEX_COORDINATES;
		vertexCenter = (float3) (vertices[vertexOffset], vertices[vertexOffset + 1], vertices[vertexOffset + 2]);
		vertexNorth = (float3) (vertices[vertexOffsetNorth], vertices[vertexOffsetNorth + 1], vertices[vertexOffsetNorth + 2]);
		vertexEast = (float3) (vertices[vertexOffsetEast], vertices[vertexOffsetEast + 1], vertices[vertexOffsetEast + 2]);
		vertexSouth = (float3) (vertices[vertexOffsetSouth], vertices[vertexOffsetSouth + 1], vertices[vertexOffsetSouth + 2]);
		normalNortheast = normalize(cross(vertexEast - vertexCenter, vertexNorth - vertexCenter));
		normalSoutheast = normalize(cross(vertexSouth - vertexCenter, vertexEast - vertexCenter));
		if (longitude + 1 < longitudinalSize) {
			vertexOffsetWest = vertexOffset - directionalSize * VERTEX_COORDINATES + (CENTER - WEST) * VERTEX_COORDINATES;
			vertexWest = (float3) (vertices[vertexOffsetWest], vertices[vertexOffsetWest + 1], vertices[vertexOffsetWest + 2]);		
			normalSouthwest = normalize(cross(vertexWest - vertexCenter, vertexSouth - vertexCenter));
			normalNorthwest = normalize(cross(vertexNorth - vertexCenter, vertexWest - vertexCenter));
			normal = (normalNortheast + normalSoutheast + normalSouthwest + normalNorthwest) / 4.0f;
		} else
			normal = (normalNortheast + normalSoutheast) / 2.0f;
		break;
	case NORTHWEST:
		normal = (float3) (0.0f, -1.0f, 0.0f);
		break;
	case CENTER:
		vertexOffsetNorth = vertexOffset + (NORTH - CENTER) * VERTEX_COORDINATES;
		vertexOffsetNortheast = vertexOffset + (NORTHEAST - CENTER) * VERTEX_COORDINATES;
		vertexOffsetEast = vertexOffset + (EAST - CENTER) * VERTEX_COORDINATES;
		vertexOffsetSoutheast = vertexOffset + (SOUTHEAST - CENTER) * VERTEX_COORDINATES;
		vertexOffsetSouth = vertexOffset + (SOUTH - CENTER) * VERTEX_COORDINATES;
		vertexOffsetSouthwest = vertexOffset + (SOUTHWEST - CENTER) * VERTEX_COORDINATES;
		vertexOffsetWest = vertexOffset + (WEST - CENTER) * VERTEX_COORDINATES;
		vertexOffsetNorthwest = vertexOffset + (NORTHWEST - CENTER) * VERTEX_COORDINATES;
		vertexCenter = (float3) (vertices[vertexOffset], vertices[vertexOffset + 1], vertices[vertexOffset + 2]);
		vertexNorth = (float3) (vertices[vertexOffsetNorth], vertices[vertexOffsetNorth + 1], vertices[vertexOffsetNorth + 2]);
		vertexNortheast = (float3) (vertices[vertexOffsetNortheast], vertices[vertexOffsetNortheast + 1], vertices[vertexOffsetNortheast + 2]);
		vertexEast = (float3) (vertices[vertexOffsetEast], vertices[vertexOffsetEast + 1], vertices[vertexOffsetEast + 2]);
		vertexSoutheast = (float3) (vertices[vertexOffsetSoutheast], vertices[vertexOffsetSoutheast + 1], vertices[vertexOffsetSoutheast + 2]);
		vertexSouth = (float3) (vertices[vertexOffsetSouth], vertices[vertexOffsetSouth + 1], vertices[vertexOffsetSouth + 2]);
		vertexSouthwest = (float3) (vertices[vertexOffsetSouthwest], vertices[vertexOffsetSouthwest + 1], vertices[vertexOffsetSouthwest + 2]);
		vertexWest = (float3) (vertices[vertexOffsetWest], vertices[vertexOffsetWest + 1], vertices[vertexOffsetWest + 2]);
		vertexNorthwest = (float3) (vertices[vertexOffsetNorthwest], vertices[vertexOffsetNorthwest + 1], vertices[vertexOffsetNorthwest + 2]);
		normalNorthNortheast = normalize(cross(vertexNortheast - vertexCenter, vertexNorth - vertexCenter));
		normalNortheastEast = normalize(cross(vertexEast - vertexCenter, vertexNortheast - vertexCenter));
		normalEastSoutheast = normalize(cross(vertexSoutheast - vertexCenter, vertexEast - vertexCenter));
		normalSoutheastSouth = normalize(cross(vertexSouth - vertexCenter, vertexSoutheast - vertexCenter));
		normalSouthSouthwest = normalize(cross(vertexSouthwest - vertexCenter, vertexSouth - vertexCenter));
		normalSouthwestWest = normalize(cross(vertexWest - vertexCenter, vertexSouthwest - vertexCenter));
		normalWestNorthwest = normalize(cross(vertexNorthwest - vertexCenter, vertexWest - vertexCenter));
		normalNorthwestNorth = normalize(cross(vertexNorth - vertexCenter, vertexNorthwest - vertexCenter));
		normal = (normalNorthNortheast + normalNortheastEast + normalEastSoutheast + normalSoutheastSouth + normalSouthSouthwest + normalSouthwestWest + normalWestNorthwest + normalNorthwestNorth) / 8.0f;
	}
	normals[vertexOffset] = normal.x;
	normals[vertexOffset + 1] = normal.y;
	normals[vertexOffset + 2] = normal.z;
}
